package com.example.origin.spider.utils;


import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.LinkedHashMap;

@Slf4j
@UtilityClass
public class HttpClientUtil {


    private static RequestConfig getRequestConfig() {
        //配器请求信息
        RequestConfig config = RequestConfig.custom().setConnectTimeout(1000)//创建连接的最长时间，单位是毫秒
                .setConnectionRequestTimeout(5000)//设置获取连接的最长时间，单位是毫秒
                .setSocketTimeout(10 * 1000) //设置数据传输的最长时间，单位是豪秒
                .build();
        return config;
    }

    private static PoolingHttpClientConnectionManager getConnectionManager() {
        //创建连接池管理器
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        //设置最大连接数
        cm.setMaxTotal(100);
        //设置每个主机的最大连接数
        cm.setDefaultMaxPerRoute(10);
        return cm;
    }

    @SneakyThrows
    public <P, T> T post(String url, P body, LinkedHashMap<String, String> headers, TypeReference<T> resultReference) {

        PoolingHttpClientConnectionManager connectionManager = getConnectionManager();
        RequestConfig requestConfig = getRequestConfig();

        //创建HttpC1ient对象
        CloseableHttpClient httpclient = HttpClients.custom().setConnectionManager(connectionManager).build();
        //创建HttpPost,对象，设置urI访问地址
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);
        headers.forEach(httpPost::addHeader);

        //设置表单的Entity对象到Post请求中
        StringEntity s = new StringEntity(JSONUtil.toJsonStr(body));
        s.setContentEncoding("UTF-8");
        s.setContentType("application/json");//发送json数据需要设置contentType
        httpPost.setEntity(s);

        try (//使用Httpclient发起请求，获取response
             CloseableHttpResponse response = httpclient.execute(httpPost)) {
            //解析响应
            if (response.getStatusLine().getStatusCode() == 200) {
                return getResult(resultReference, response);
            } else {
                throw new RuntimeException(response.getStatusLine().getStatusCode() + ":" + response.getStatusLine().getReasonPhrase());
            }
        }
    }

    private static <T> T getResult(TypeReference<T> resultReference, CloseableHttpResponse response) throws IOException {
        HttpEntity entity = response.getEntity();
        String string = EntityUtils.toString(entity, Charset.defaultCharset());
        return JSON.parseObject(string, resultReference);
    }

    @SneakyThrows
    public <T> T get(String url, LinkedHashMap<String, String> headers, TypeReference<T> resultReference) {

        PoolingHttpClientConnectionManager connectionManager = getConnectionManager();
        RequestConfig requestConfig = getRequestConfig();

        //创建HttpC1ient对象
        CloseableHttpClient httpclient = HttpClients.custom().setConnectionManager(connectionManager).build();
        //创建HttpGet,对象，设置urI访问地址
        HttpGet httpGet = new HttpGet(url);
        httpGet.setConfig(requestConfig);
        headers.forEach(httpGet::addHeader);

        try (//使用Httpclient发起请求，获取response
             CloseableHttpResponse response = httpclient.execute(httpGet)) {
            //解析响应
            if (response.getStatusLine().getStatusCode() == 200) {
                return getResult(resultReference, response);
            } else {
                throw new RuntimeException(response.getStatusLine().getStatusCode() + ":" + response.getStatusLine().getReasonPhrase());
            }
        }
    }
}
